/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package hxg.portmgr.core.oper.snmp;


import hxg.portmgr.core.arp.VlanMacPort;
import hxg.portmgr.core.device.Switch.TrafficLimit;
import hxg.portmgr.core.device.intf.Intf;
import hxg.portmgr.core.device.intf.VlanL2;
import hxg.portmgr.core.oper.snmp.oidgroup.SwitchVlanOidEntry;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.Variable;

/**
 *
 * @author hxg
 */
public class SwitchSnmpOper extends SnmpOper {

    private static final Logger logger = Logger.getLogger(SwitchSnmpOper.class.getName());

    public SwitchSnmpOper(String ip, String readCommunity, String writeCommunity) {
        super(ip, readCommunity, writeCommunity);
    }

    public List<String> getMacListOfIntf(Intf inf) {
        List<String> list = new ArrayList();
        return list;
    }

    public List<VlanMacPort> getVlanMacPortList() throws IOException {
        List<VlanMacPort> list = new ArrayList();
        OID[] oids = new OID[]{
            new OID(VlanMacPort.dot1qTpFdbPort)
        };
        Map<OID, Map<OID, Variable>> mp = SnmpOperUtils.getVariablelTableOfOIDs(oids, SnmpOperUtils.getTarget(ip, readCommunity));
        System.out.println(mp);
        for (Entry<OID, Map<OID, Variable>> varentry : mp.entrySet()) {
            OID ifoid = varentry.getKey();
            String ifidx = varentry.getValue().get(oids[0]).toString();
            //String mac = varentry.getValue().get(oids[1]).toString();
            int[] ss = ifoid.toIntArray();
            int vlan = ss[0];
            int[] mac = new int[6];
            for (int i = 0; i < 6; i++) {
                mac[i] = ss[i + 1];
            }
            VlanMacPort vmc = VlanMacPort.createVlanMacPort(mac, vlan, ifidx);
            System.out.println(mac + ";" + vlan + ";" + ifidx);
            list.add(vmc);
        }
        return list;

    }

//    public List<TrafficLimit> getTrafficLimit(String ifidx) throws IOException {
//        List<TrafficLimit> traffics = new ArrayList<>();
//        OID[] oids = new OID[2];
//        oids[0] = HwCBQosIfApplyPolicy.hwCBQoSIfApplyPolicyDirection.getAppendOID(new OID(ifidx));
//        oids[1] = HwCBQosIfApplyPolicy.hwCBQoSIfApplyPolicyName.getAppendOID(new OID(ifidx));
//        Map<OID, Map<OID, Variable>> mp = SnmpOperUtils.getVariablelTableOfOIDs(oids, SnmpOperUtils.getTarget(ip, readCommunity));
//        for (OID ifOid : mp.keySet()) {
//            TrafficLimit limit = new TrafficLimit();
//        }
//        return traffics;
//    }

    protected List<VlanL2> getVlans() throws IOException {
        List<VlanL2> list = new ArrayList<>();
        System.out.println("1");
        //Map<OID,Map<SwitchVlanOidEntry,Variable>> mp= SnmpOperUtils.getVariblesOfOidEntryByRow(new SwitchVlanOidEntry[]{SwitchVlanOidEntry.dot1qVlanFdbId}, SnmpOperUtils.getTarget(ip, readCommunity));
        //System.out.println(mp);
        for (Entry<OID, Variable> entry : SnmpOperUtils.getList(SwitchVlanOidEntry.dot1qVlanFdbId.getOID(), SnmpOperUtils.getTarget(ip, readCommunity)).entrySet()) {
            VlanL2 vlan = new VlanL2();
            vlan.setVlan(entry.getValue().toInt());
            vlan.setIndex(entry.getKey().toString());
            list.add(vlan);
        }
        return list;
    }

    /**
     *
     * @return vlan2对应的Intf的index表,第一个列表是Tagged的列表,第二个是Untagged的列表
     * 一般来说,接口index的index应该是int型的,但是为了和程序保持一致,就选择了String
     * @throws IOException
     */
    protected Map<VlanL2, ArrayList<String>[]> getVlanAndPortMap() throws IOException {
        Map<VlanL2, ArrayList<String>[]> mp = new LinkedHashMap<>();
        Map<OID, Map<SwitchVlanOidEntry, Variable>> ifNo2IndexMp =
                SnmpOperUtils.getVariblesOfOidEntryByRow(
                new SwitchVlanOidEntry[]{SwitchVlanOidEntry.dot1dBasePortIfIndex},
                SnmpOperUtils.getTarget(ip, readCommunity));
        Map<Integer, String> intfmp = new HashMap<>();
        for (Entry<OID, Map<SwitchVlanOidEntry, Variable>> entry : ifNo2IndexMp.entrySet()) {
            intfmp.put(Integer.valueOf(entry.getKey().toString()), entry.getValue().get(SwitchVlanOidEntry.dot1dBasePortIfIndex).toString());
        }
        System.out.println(intfmp);
        Map<OID, Map<SwitchVlanOidEntry, Variable>> retmp =
                SnmpOperUtils.getVariblesOfOidEntryByRow(
                new SwitchVlanOidEntry[]{SwitchVlanOidEntry.dot1qVlanFdbId, SwitchVlanOidEntry.dot1qVlanCurrentEgressPorts, SwitchVlanOidEntry.dot1qVlanCurrentUntaggedPorts},
                SnmpOperUtils.getTarget(ip, readCommunity));

        for (Entry<OID, Map<SwitchVlanOidEntry, Variable>> entry : retmp.entrySet()) {
            try {
                VlanL2 vlan = new VlanL2();
                OID oid = entry.getKey();
                int vlanid = entry.getValue().get(SwitchVlanOidEntry.dot1qVlanFdbId).toInt();
                String taggedVlanOctValue = entry.getValue().get(SwitchVlanOidEntry.dot1qVlanCurrentEgressPorts).toString();
                String untaggedVlanOctValue = entry.getValue().get(SwitchVlanOidEntry.dot1qVlanCurrentUntaggedPorts).toString();
                vlan.setVlan(vlanid);
                vlan.setIndex(oid.toString());
                List<Integer> taggedIntfNums = transOctString2PortNums(taggedVlanOctValue, ':',-1);
                List<Integer> untaggedIntfNums = transOctString2PortNums(untaggedVlanOctValue, ':',-1);
                ArrayList<String> taggedIntfIndexs = new ArrayList<>();
                ArrayList<String> untaggedIntfIndexs = new ArrayList<>();
                for (int taggednum : taggedIntfNums) {
                    taggedIntfIndexs.add(intfmp.get(taggednum).toString());
                }
                for (int untaggednum : untaggedIntfNums) {
                    untaggedIntfIndexs.add(intfmp.get(untaggednum).toString());
                }
                //ArrayList<String>[] intflist=new ArrayList[]{taggedIntfIndexs, untaggedIntfIndexs};
                mp.put(vlan, new ArrayList[]{taggedIntfIndexs, untaggedIntfIndexs});
            } catch (Exception e) {
                //System.out.println(taggednum);
                logger.log(Level.INFO, null, e);
            }
        }
        return mp;
    }

    /**
     * PortList,以二进制字符串表示,如FF:FE:4D 等等,以二进制表示为11111111,11111110,00101101,其中1的值所在位置就表示对应的接口的序号(非索引,对应的索引用dot1qVlanFdbId表找)
     * 比如上面就是[1,2,3,...15,19,21,22,24]号端口
     * @param str
     * @param ch 分隔用字符,如FF:FE:4D中的':'
     * @param offset 偏移量,原始的PortList如03:FF为0000001111111111,应该对应[7,8,9,...,16]但是有设备确在实际上表示的是[6,7,8,...15],这时应该用offset=-1,左偏移一位
     * @return 
     */
    final protected List<Integer> transOctString2PortNums(String str, char ch,int offset) {
        ArrayList<Integer> arrs = new ArrayList<>();
        OctetString ocs = OctetString.fromHexString(str, ch);
        int k = 0;
        for (byte b : ocs.getValue()) {
            int i = b >= 0 ? b : b + 256;
            if (b != 0) {
                for (int n = 7; n >= 0; n--) {
                    int mask = n > 0 ? 2 << n - 1 : 1;//2的n次阶乘,当n=0时应该为1,但是左移不可能为-1
                    //用2的n次阶乘生成如00100000的二进制数字,然后按位进行'与'操作,判断1所在位置的值是否为1, n就1所在位置
                    if ((i & mask) > 0) {
                        arrs.add(8 - n + k+offset);
                    }
                }
            }
            k = k + 8;
        }
        return arrs;
    }

    public Map<Integer, ArrayList<Intf>> getVlanAndIntfMap() {
        Map<Integer, ArrayList<Intf>> mp = new LinkedHashMap<>();
        return mp;
    }
}
